/*---------------------------------------------------------------------------
 *  File Name: sthread.cc
 *
 *  Purpose:  define the sthreads (dart simulation)
 *
 *  Usage: 
 *
 *  Description:
 *
 *  Major Data Structure: 
 *
 *  Caution:
 *
 *  Programmer: Sharon Galtzur
 *
 *  Revision History:
 *
 *
 *
 *--------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------
 * include files
 *--------------------------------------------------------------------------*/
#ifndef WIN32
#ifndef HPUX
#include <thread.h>
#endif /* HPUX */
#endif // WIN32
#ifdef HPUX
#include <pthread.h>
#endif /* HPUX */
#include "dartdefs.hxx"
#include "sthread.hxx"
#include "threads_db.hxx"
#include "revisions.hxx"

/*------------------------------------------------------------------
 * RCS info recording
 *----------------------------------------------------------------*/
static Revision revision("$Author: cal-proj $",
		       "$Date: 2002/03/06 03:41:00 $",
		       "$RCSfile: sthread.cc,v $",
		       "$Revision: 11.0 $" );
#ifndef WIN32
/*---------------------------------------------------------------------------
 * defines & macros
 *--------------------------------------------------------------------------*/

#define Sthread_Head int

/*---------------------------------------------------------------------------
 * global variables
 *--------------------------------------------------------------------------*/

static Sthread sthread_fake("sthread_fake");
 
/*---------------------------------------------------------------------------
 * functions
 *--------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------
 * Function Name: Sthread::*
 *
 * Purpose: define all the mutex func
 *
 * Returns: 
 *
 *-------------------------------------------------------------------------*/
Sthread::Sthread(const char *nameStr, 
		 Sthread_Head *free_q,
		 unsigned stk_size) {

  /* these are just to remove comiler warrnings */
  if( nameStr == NULL ) 
    return ; 
  if( free_q != NULL ) 
    return ; 
  if( stk_size == 0 )
    return ; 

} /* END Sthread::Sthread */

void Sthread::startThread(Sthread_Initial *i) {

  i->start();

} /* END Sthread::startThread */

void Sthread::suicide() {

#ifdef HPUX
  pthread_exit(NULL);
#else /* HPUX */
  thr_exit(NULL);
#endif /* HPUX */

} /* END Sthread::suicide */

void Sthread::yield() {

#ifdef HPUX
  sched_yield();
#else /* HPUX */
  thr_yield();
#endif /* HPUX */

} /* END Sthread::yield */

#ifdef LINUX
pthread_key_t Sthread::cbkpThreadNumKey = 0xffffffff;
uint Sthread::nLinuxThreads = 0;
#endif /* LINUX */

uint Sthread::tag() {

#ifdef HPUX
#ifdef LINUX
  int ret;
  void *pRet;
  uint newVal;
  uint *pVal;

  if (cbkpThreadNumKey == 0xffffffff) {
    ret = pthread_key_create(&cbkpThreadNumKey, NULL);
    if (ret != 0) {
      printf("pthread_key_create returned %d\n", ret);
      exit(1);
    }
  }
  pRet = pthread_getspecific(cbkpThreadNumKey);
  if (pRet == NULL) {
    // should be in a mutex!
    newVal = nLinuxThreads++;
    pVal = new uint;
    *pVal = newVal;
    ret = pthread_setspecific(cbkpThreadNumKey, (void *) pVal);
    if (ret != 0) {
      printf("pthread_setspecific returned %d\n", ret);
      exit(1);
    }
    return newVal;
  }

  pVal = (uint *) pRet;
  return *pVal;
    
#else /* LINUX */

  return (uint) pthread_self();

#endif /* LINUX */

#else /* HPUX */

  return (uint) thr_self();

#endif /* HPUX */

} /* END Sthread::tag */



/*---------------------------------------------------------------------------
 * Function Name: Sthread_self::*
 *
 * Purpose: return a poniter to the current thread (in sim the fake thread)
 *
 * Returns: 
 *
 *-------------------------------------------------------------------------*/
Sthread* Sthread_self(void) {

  return &sthread_fake;

} /* END Sthread_self */

#else /* WIN32 */

/*---------------------------------------------------------------------------
 * defines & macros
 *--------------------------------------------------------------------------*/

#define Sthread_Head int

/*---------------------------------------------------------------------------
 * global variables
 *--------------------------------------------------------------------------*/

static Sthread sthread_fake("sthread_fake");
 
/*---------------------------------------------------------------------------
 * functions
 *--------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------
 * Function Name: Sthread::*
 *
 * Purpose: define all the mutex func
 *
 * Returns: 
 *
 *-------------------------------------------------------------------------*/
Sthread::Sthread(char *nameStr, 
		 Sthread_Head *free_q,
		 unsigned stk_size) {

  ulong n;

  if (win32ThreadIdTbl == NULL) {
    if ((win32ThreadIdTbl = new DWORD[MAX_N_THREADS_EVER + 1] ) == NULL ) {
      BUG(MALLOC_FAILED);
    }
  
    for( n=0; n < MAX_N_THREADS_EVER + 1; n++ ) {
      win32ThreadIdTbl[n] = NOT_AN_ENTRY;
    }
  }

  /* these are just to remove comiler warrnings */
  if( nameStr == NULL ) 
    return ; 
  if( free_q != NULL ) 
    return ; 
  if( stk_size == 0 )
    return ; 

} /* END Sthread::Sthread */

void Sthread::startThread(Sthread_Initial *i) {

  i->start();

} /* END Sthread::startThread */

void Sthread::suicide() {

  ExitThread(0);

} /* END Sthread::suicide */

void Sthread::yield() {

  /* WINNT only SwitchToThread(); */
#undef Sleep
  Sleep(0);

} /* END Sthread::yield */

uint Sthread::tag() {

  uint i;

  DWORD tn = GetCurrentThreadId();

  i = Lookup(tn);

  return i;

} /* END Sthread::tag */

DWORD *Sthread::win32ThreadIdTbl = NULL;
ulong Sthread::nWin32Threads = 0;

uint Sthread::Lookup(DWORD win32ThreadId)
{
  uint i;

  for (i = 0; i < nWin32Threads; i++) {
    if (win32ThreadIdTbl[i] == win32ThreadId) {
      return i;
    }
  }
  // not found - add it!
  i = nWin32Threads++;
  win32ThreadIdTbl[i] = win32ThreadId;
  return i;
}


/*---------------------------------------------------------------------------
 * Function Name: Sthread_self::*
 *
 * Purpose: return a poniter to the current thread (in sim the fake thread)
 *
 * Returns: 
 *
 *-------------------------------------------------------------------------*/
Sthread* Sthread_self(void) {

  return &sthread_fake;

} /* END Sthread_self */

#endif /* WIN32 */

/* END of FILE  sthread.cc! */
